#include "ObjectMgr.h"
#include "Common/TableDataEx/DeputyCfg.h"
#include "Character/CreatureMgr.h"
#include "Character/monster/MonsterRefCfg.h"
#include "Character/monster/Monster.h"
#include "base/core/random.h"

ObjectMgr::ObjectMgr()
{
	m_mapSceneObject.clear();
	m_mapSceneFresh.clear();
}

ObjectMgr::~ObjectMgr()
{
}

bool ObjectMgr::Init()
{
	return true;
}

bool ObjectMgr::UnInit()
{
	m_mapSceneObject.clear();
	m_mapSceneFresh.clear();
	return true;
}

bool ObjectMgr::Update(uint64_t tick)
{
	MapSceneFresh::iterator iter = m_mapSceneFresh.begin();
	while (iter != m_mapSceneFresh.end())
	{
		if (!g_GetSceneMgr()->GetScene(iter->first))
		{
			iter = m_mapSceneFresh.erase(iter);
			continue;
		}
		bool bFlag = false;
		MAP_UINT32_MULTI_SET_UINT64 &mapSet = iter->second;
		MAP_UINT32_MULTI_SET_UINT64::iterator iterUpdate = mapSet.begin();
		while (iterUpdate != mapSet.end())
		{
			bool bFresh = false;
			uint32_t objectId = iterUpdate->first;
			MULTI_SET_UINT64 &setInt = iterUpdate->second;
			MULTI_SET_UINT64::iterator iterSet = setInt.begin();
			while (iterSet != setInt.end())
			{
				uint64_t freshTick = (*iterSet);
				if (freshTick > tick)
				{
					++iterSet;
					continue;
				}

				//这里需要刷新
				FreshObject(iter->first, objectId);

				bFresh = true;
				iterSet = setInt.erase(iterSet);
			}
			if (bFresh && setInt.empty())
			{
				iterUpdate = mapSet.erase(iterUpdate);
				bFlag = true;
			}
			else
			{
				++iterUpdate;
			}
		} // end of while (iterUpdate != mapSet.end())
		if (bFlag && mapSet.empty())
		{
			iter = m_mapSceneFresh.erase(iter);
		}
		else
		{
			++iter;
		}
	}

	return true;
}

bool ObjectMgr::FreshObject(uint32_t sceneId, uint32_t objectId)
{
	Scene *pScene = g_GetSceneMgr()->GetScene(sceneId);
	if (nullptr == pScene)
	{
		return false;
	}
	uint32_t mapId = pScene->GetMapId();
	const ThingCollectCfgInfo *pCollectCfg = g_GetDeputyCfgMgr()->GetMapThingCollectCfgInfo(objectId);
	if (nullptr == pCollectCfg)
	{
		return true;
	}
	//这里需要从配置中随机一个刷新点出来
	FreshObject(pCollectCfg, mapId, sceneId, objectId, 1);
	return true;
}

SET_INT32 *ObjectMgr::GetSceneObject(uint32_t sceneId, uint32_t objectId)
{
	MapSceneObject::iterator iter = m_mapSceneObject.find(sceneId);
	if (iter != m_mapSceneObject.end())
	{
		MAP_UINT32_SET_INT32 &mapSet = iter->second;
		MAP_UINT32_SET_INT32::iterator iterSet = mapSet.find(objectId);
		return (iterSet != mapSet.end()) ? &iterSet->second : nullptr;
	}
	return nullptr;
}

//创建矿石
Object *ObjectMgr::CreateObject(uint32_t nObjectId, uint32_t nSceneId, Point3<float>& bornPos, int32_t posIdx)
{
	g_GetCreatureMgr()->CreateObject(nObjectId, nSceneId, bornPos, posIdx);

	//LogDebugFmtPrint("[logic] ObjectMgr::CreateObject...cid:%u ,objectId:%u, sceneId:%u, posIdx:%d, dstpos(%f,%f,%f)", pMine->GetCid(), nObjectId, nSceneId, posIdx, bornPos.x, bornPos.y, bornPos.z);

	MapSceneObject::iterator iter = m_mapSceneObject.find(nSceneId);
	if (iter != m_mapSceneObject.end())
	{
		MAP_UINT32_SET_INT32 &mapSet = iter->second;
		MAP_UINT32_SET_INT32::iterator iterSet = mapSet.find(nObjectId);
		if (iterSet != mapSet.end())
		{
			iterSet->second.insert(posIdx);
		}
		else
		{
			SET_INT32 setInt;
			setInt.insert(posIdx);
			mapSet[nObjectId] = setInt;
		}
	}
	else
	{
		MAP_UINT32_SET_INT32 mapSet;
		SET_INT32 setMine;
		setMine.insert(posIdx);
		mapSet[nObjectId] = setMine;
		m_mapSceneObject[nSceneId] = mapSet;
	}

	return nullptr;
}

Object *ObjectMgr::CreateObjectByChar(uint32_t nObjectId, uint32_t nSceneId, Point3<float>& bornPos, CharIDType charId)
{
	Object *pObject = g_GetCreatureMgr()->CreateObject(nObjectId, nSceneId, bornPos, -1);
	if (pObject)
	{
		pObject->SetSeenCharId(charId);
	}
	return pObject;
}

bool ObjectMgr::CollectScuess(Creature *creat, bool fresh)
{
	if (nullptr == creat)
	{
		return false;
	}

	if (!CheckPeel(creat))
	{
		return false;
	}

	Object* pObject = (Object*)creat;
	if (nullptr == pObject)
	{
		LogErrFmtPrint("[logic] ObjectMgr::RecycleObject....nullptr == pObject.....cid :%u", creat->GetCid());
		return false;
	}

	if (fresh && !CheckRecycle(pObject))
	{
		return false;
	}

	if (!pObject->LeaveScene())
	{
		return false;
		//下一帧准备等待回收
		//g_GetCreatureMgr()->WaitDestory(pObject->GetCid());
		//g_GetCreatureMgr()->WaitDestory(creat);
	}

	uint32_t cfgId = pObject->GetConfigId();
	int32_t posIdx = pObject->GetPosIdx();

	//从场景记录中删除
	uint32_t sceneId = pObject->GetSceneId();
	MapSceneObject::iterator iterObject = m_mapSceneObject.find(sceneId);
	if (iterObject != m_mapSceneObject.end())
	{
		MAP_UINT32_SET_INT32 &mapSet = iterObject->second;
		MAP_UINT32_SET_INT32::iterator iterSet = mapSet.find(cfgId);
		if (iterSet != mapSet.end())
		{
			iterSet->second.erase(posIdx);
			if (iterSet->second.empty())
			{
				mapSet.erase(iterSet);
			}
		}
		if (mapSet.empty())
		{
			m_mapSceneObject.erase(iterObject);
		}
	}

	//只对某个角色可见的采集物 不再刷新
	if (pObject->GetSeenCharId() > 0)
	{
		g_GetCreatureMgr()->Destory(pObject);
		return true;
	}

	switch (pObject->GetType())
	{
	case CollectData_Type_Herbs:
	case CollectData_Type_Mine:
	case CollectData_Type_Other:
	case CollectData_Type_Fish:
	{
		if (fresh)
			Add2FreshMap(pObject);
	}
	break;
	default:
		break;
	}

	if (pObject)
		g_GetCreatureMgr()->Destory(pObject);

	return true;
}

void ObjectMgr::Add2FreshMap(Object *pObject)
{
	if (nullptr == pObject)
	{
		return;
	}
	const ThingCollectCfgInfo *pcfg = pObject->GetObjectCfg();
	if (nullptr != pcfg)
	{
		//插入到刷新的tick列表中
		uint32_t cfgId = pObject->GetConfigId();
		uint32_t sceneId = pObject->GetSceneId();
		uint64_t tick = g_GetGlobalServerTime()->Tick() + pcfg->refreshTime;
		MapSceneFresh::iterator iterFresh = m_mapSceneFresh.find(sceneId);
		if (iterFresh != m_mapSceneFresh.end())
		{
			MAP_UINT32_MULTI_SET_UINT64 &mapUpdate = iterFresh->second;
			MAP_UINT32_MULTI_SET_UINT64::iterator iterEx = mapUpdate.find(cfgId);
			if (iterEx != mapUpdate.end())
			{
				MULTI_SET_UINT64 &setTick = iterEx->second;
				setTick.insert(tick);
			}
			else
			{
				MULTI_SET_UINT64 setTick;
				setTick.insert(tick);
				mapUpdate[cfgId] = setTick;
			}
		}
		else
		{
			MAP_UINT32_MULTI_SET_UINT64 mapUpdate;
			MULTI_SET_UINT64 setTick;
			setTick.insert(tick);
			mapUpdate[cfgId] = setTick;
			m_mapSceneFresh[sceneId] = mapUpdate;
		}
	}
}

void ObjectMgr::InitSceneObject(const LstCollectCfg &objectLst, uint32_t mapId, uint32_t sceneId)
{
	LstCollectCfg::const_iterator iter = objectLst.begin();
	for (; iter != objectLst.end(); ++iter)
	{
		const ThingCollectCfgInfo *pCollectCfg = (*iter);
		if (nullptr == pCollectCfg)
		{
			LogErrFmtPrint("[logic] ObjectMgr::InitSceneObject....pCollectCfg == nullptr");
			continue;
		}
		FreshObject(pCollectCfg, mapId, sceneId, pCollectCfg->id, pCollectCfg->makeCount);
	}
}

bool ObjectMgr::CheckPeel(Creature *creat)
{
	if (CREATURE_MONSTER != creat->CreatureKind())
	{
		return true;
	}

	Monster* pMonster = dynamic_cast<Monster*>(creat);
	if (nullptr == pMonster)
	{
		LogErrFmtPrint("[logic] ObjectMgr::CheckPeel....nullptr == pMonster...cid:%u ", creat->GetCid());
		return false;
	}
	pMonster->SetBoPiNum(pMonster->GetBoPiNum() + 1);
	pMonster->OnDestroyMonsterNow();
	return false;
}

bool ObjectMgr::CheckRecycle(Object *pObject)
{
	if (pObject->GetCount() <= 1)
		return true;

	pObject->SetCount(pObject->GetCount() - 1);
	return false;
}

bool ObjectMgr::FreshObject(const ThingCollectCfgInfo *pCollectCfg, uint32_t mapId, uint32_t sceneId, uint32_t objectId, uint32_t count)
{
	if (nullptr == pCollectCfg)
	{
		return false;
	}
	const CollectRefLocation *pCollLoc = g_GetMapLocationCfg()->GetCollectRefLoc(objectId);
	if (nullptr == pCollLoc)
	{
		LogErrFmtPrint("[logic] ObjectMgr::FreshObject.....nullptr == pCollLoc ...id:%d, mapid:%u ,seceneid:%u ", objectId, mapId, sceneId);
		return false;
	}
	int32_t isize = pCollLoc->m_vecPos.size();
	if (isize <= 0)
	{
		return true;
	}
	SET_INT32 *pSetObjectIdx = GetSceneObject(sceneId, objectId);
	VecPoint3 vecFreshPos;
	VEC_INT32 vecIdx;
	for (int32_t i = 0; i < isize; ++i)
	{
		if (nullptr != pSetObjectIdx)
		{
			SET_INT32::iterator iterFind = pSetObjectIdx->find(i);
			if (iterFind != pSetObjectIdx->end())
			{
				continue;
			}
		}
		vecFreshPos.push_back(pCollLoc->m_vecPos[i]);
		vecIdx.push_back(i);
	}

	int32_t freshSize = vecFreshPos.size();
	if (freshSize < (int32_t)count)
	{
		LogErrFmtPrint("[logic] ObjectMgr::FreshObject....has not enough object .....id:%u ,mapid:%u, count:%d, realsize:%d ", objectId, mapId, count, vecFreshPos.size());
	}

	for (int32_t j = 0; j < (int32_t)count; ++j)
	{
		if (freshSize <= 0)
		{
			break;
		}
		int32_t idx = Random(freshSize);
		Point3<float> pos = vecFreshPos[idx];
		CreateObject(objectId, sceneId, pos, vecIdx[idx]);

		vecFreshPos.erase(vecFreshPos.begin() + idx);
		vecIdx.erase(vecIdx.begin() + idx);
		freshSize -= 1;
	}

	return true;
}
